package com.ecarx.module_network;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.text.TextUtils;
import android.util.Log;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class WifiApManager {
    private static final String TAG = "WifiApManager";
    // current wifi ap state
    int curState;

    // wifi ap state enum
    public interface APStatus {
        int DISABLING = 10;
        int DISABLED = 11;
        int ENABLING = 12;
        int ENABLED = 13;
    }

    private WifiManager mWifiManager;
    private Context mContext;
    private WifiConfiguration mWifiConfiguration;

    private boolean mShouldRestart = false; // Flag for change SSID or PSWD need reboot AP
    private boolean mStartReboot = false; // fwk may receive ap open broadcast，but this moment ap does not restart，use "mStartReboot" flag to keep restarting
    private WifiAPCallBack mWifiAPCallBack; // translate data to Fragment

    private static final String METHOD_GET_WIFI_AP_STATE = "getWifiApState";
    private static final String METHOD_GET_WIFI_AP_CONFIG = "getWifiApConfiguration";
    private static final String METHOD_SET_WIFI_AP_CONFIG = "setWifiApConfiguration";
    private static final String AP_STATE_ACTION = "android.net.wifi.WIFI_AP_STATE_CHANGED";
    public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
    public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";

    public WifiApManager(Context context) {
        mContext = context;
        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
        final IntentFilter filter = new IntentFilter();
        filter.addAction(AP_STATE_ACTION);
        mContext.registerReceiver(mReceiver, filter);
    }

    // set call back for data translate between fragment and Manager
    public void setWifiCallBack(WifiAPCallBack wifiAPCallBack) {
        this.mWifiAPCallBack = wifiAPCallBack;
    }

    // AP statue change, we will get the broadcast and refresh info
    public BroadcastReceiver mReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            Log.i(TAG, "onReceive-" + action);
            if (AP_STATE_ACTION.equals(action)) {
                final int apState = intent.getIntExtra(EXTRA_WIFI_AP_STATE, 0);
                final int previousState = intent.getIntExtra(EXTRA_PREVIOUS_WIFI_AP_STATE, 0);
                recWifiApStatus(apState, previousState);
            }
        }

    };

    // when engineerMode init, get ap statue
    public boolean getApStateWhetherOpen() {
        curState = APStatus.DISABLED;
        try {
            Method method = mWifiManager.getClass().getMethod(
                    METHOD_GET_WIFI_AP_STATE);
            curState = (Integer) method.invoke(mWifiManager);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return curState == APStatus.ENABLED;
    }

    // get ap info include SSID and password
    public void getWifiApInfoAsyn() {
        try {
            Method method = mWifiManager.getClass().getMethod(
                    METHOD_GET_WIFI_AP_CONFIG);
            mWifiConfiguration = (WifiConfiguration) method.invoke(mWifiManager);
            if (mWifiConfiguration != null && mWifiAPCallBack != null) {
                Log.d(TAG, "transWifiAPConfigInfo SSID is:" + mWifiConfiguration.SSID);
                Log.d(TAG, "transWifiAPConfigInfo preSharedKey is:" + mWifiConfiguration.preSharedKey);
                mWifiAPCallBack.transWifiAPConfigInfo(mWifiConfiguration.SSID, mWifiConfiguration.preSharedKey);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        Log.i(TAG, "getWifiApInfo is end");
    }

    // before restart ap, need change ap config
    private boolean setAPConfiguration(WifiConfiguration config) {
        boolean isSuccess = false;
        Method method;
        try {
            method = mWifiManager.getClass().getMethod(
                    METHOD_SET_WIFI_AP_CONFIG, WifiConfiguration.class);
            isSuccess = (Boolean) method.invoke(mWifiManager, config);
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();

        }
        Log.i(TAG, "setAPConfiguration[" + config.SSID + "][" + isSuccess + "]");
        Log.d(TAG, "setAPConfiguration SSID is:" + mWifiConfiguration.SSID);
        Log.d(TAG, "setAPConfiguration preSharedKey is:" + mWifiConfiguration.preSharedKey);
        return isSuccess;
    }

    // change ap SSID
    public void changName(String name) {
        if (TextUtils.isEmpty(name)) {
            Log.d(TAG, " changName name is null");
            return;
        }
        if (mWifiConfiguration == null) {
            Log.d(TAG, "changName mWifiConfiguration is null");
            return;
        }
        Log.d(TAG, "mWifiConfiguration changName before SSID is:" + mWifiConfiguration.SSID);
        Log.d(TAG, "mWifiConfiguration changName before preSharedKey is:" + mWifiConfiguration.preSharedKey);
        mWifiConfiguration.SSID = name;
        setWifiConfigChange();
    }

    // change ap password
    public void changPswd(String pswd) {
        if (TextUtils.isEmpty(pswd)) {
            Log.d(TAG, " changPswd pswd is empty");
            return;
        }
        if (mWifiConfiguration == null) {
            Log.d(TAG, "changPswd mWifiConfiguration is null");
            return;
        }
        Log.d(TAG, "mWifiConfiguration changPswd before SSID is:" + mWifiConfiguration.SSID);
        Log.d(TAG, "mWifiConfiguration changPswd before preSharedKey is:" + mWifiConfiguration.preSharedKey);
        mWifiConfiguration.preSharedKey = pswd;
        setWifiConfigChange();
    }

    //when ap is enabled, ap info change
    private void setWifiConfigChange() {
        Log.d(TAG, "setWifiConfigChange curState is:" + curState);
        if (curState == APStatus.ENABLED) {
            mShouldRestart = true;
            setAPConfiguration(mWifiConfiguration);
            enableSoftAP(false);
        }
        Log.d(TAG, "setWifiConfigChange out");
    }

    // ap start or stop
    private boolean enableSoftAP(boolean enabled) {
        Log.d(TAG, "enableSoftAP enabled is: " + enabled);
        try {
            Method method;
            if (enabled) {
                method = mWifiManager.getClass().getMethod("startSoftAp", WifiConfiguration.class);
                Log.d(TAG, "mWifiConfiguration SSID is:" + mWifiConfiguration.SSID);
                Log.d(TAG, "mWifiConfiguration preSharedKey is:" + mWifiConfiguration.preSharedKey);
                method.invoke(mWifiManager, mWifiConfiguration);
            } else {
                method = mWifiManager.getClass().getDeclaredMethod("stopSoftAp");
                method.invoke(mWifiManager);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    // deal with ap statue change broadcast
    private void recWifiApStatus(int nowStatus, int prevStatus) {
        Log.i(TAG, "recWifiApStatus[" + nowStatus + "][" + prevStatus + "]");
        curState = nowStatus;
        if (mWifiAPCallBack != null) {
            switch (nowStatus) {
                case APStatus.ENABLING:
                    Log.i(TAG, "recWifiApStatus-AP ENABLING");
                    break;
                case APStatus.ENABLED:
                    Log.i(TAG, "recWifiApStatus-AP ENABLED");
                    getWifiApInfoAsyn();
                    mWifiAPCallBack.recWifiApState(true);
                    if (mShouldRestart && mStartReboot) {
                        mShouldRestart = false;
                        mStartReboot = false;
                        if (mWifiAPCallBack != null) {
                            mWifiAPCallBack.rebootSuccess();
                        }
                    }
                    break;
                case APStatus.DISABLING:
                    Log.i(TAG, "recWifiApStatus-AP DISABLING");
                    break;
                case APStatus.DISABLED:
                    Log.i(TAG, "recWifiApStatus-AP DISABLED");
                    getWifiApInfoAsyn();
                    mWifiAPCallBack.recWifiApState(false);
                    if (mShouldRestart) {
                        Log.i(TAG, "recWifiApStatus-AP restart");
                        /*开始重启无线热点*/
                        mStartReboot = true;
                        enableSoftAP(true);
                    }
                    break;
                default:
                    break;
            }
        }
    }

    // when ap is disabled, start ap
    public boolean openWifiAp(String name, String password) {
        Log.d(TAG, "openWifiAp curState is: " + curState);
        if (curState != APStatus.ENABLED) {
            mWifiConfiguration = new WifiConfiguration();
            mWifiConfiguration.SSID = name;
            mWifiConfiguration.allowedKeyManagement.set(4);
            mWifiConfiguration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
            mWifiConfiguration.preSharedKey = password;
            Log.d(TAG, "openWifiAp start");
            setAPConfiguration(mWifiConfiguration);
            return enableSoftAP(true);
        }
        Log.d(TAG, "openWifiAp state wrong, can not start");
        return false;
    }

    // when ap is enabled, stop ap
    public void closeWifiAp() {
        Log.d(TAG, "closeWifiAp openWifiAp curState is: " + curState);
        if (curState == APStatus.ENABLED) {
            Log.d(TAG, "closeWifiAp start");
            enableSoftAP(false);
        }
        Log.d(TAG, "closeWifiAp state wrong, can not close");
    }

    public String getWifiAddress() {
        int ipAddress = mWifiManager.getConnectionInfo().getIpAddress();
        Log.d(TAG, "getWifiAddress: " + ipAddress);
        return intToIp(ipAddress);
    }

    public String intToIp(int ipInt) {
        return (ipInt & 0xFF) + "." +
                ((ipInt >> 8) & 0xFF) + "." +
                ((ipInt >> 16) & 0xFF) + "." +
                ((ipInt >> 24) & 0xFF);
    }

}
